internal/rosa: use self-hosted stage0
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m42s
Test / Hakurei (push) Successful in 3m53s
Test / ShareFS (push) Successful in 4m3s
Test / Hpkg (push) Successful in 4m31s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 5m58s
Test / Flake checks (push) Successful in 3m10s

This removes the bootstrap dependency on Gentoo stage3 tarball.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-02-10 21:24:25 +09:00
parent fb101a02f2
commit 0061d11f93
3 changed files with 125 additions and 35 deletions

View File

@@ -111,15 +111,31 @@ func main() {
{ {
var ( var (
flagGentoo string
flagChecksum string
flagStage0 bool flagStage0 bool
) )
c.NewCommand( c.NewCommand(
"stage3", "stage3",
"Check for toolchain 3-stage non-determinism", "Check for toolchain 3-stage non-determinism",
func(args []string) (err error) { func(args []string) (err error) {
_, _, _, stage1 := (rosa.Std - 2).NewLLVM() std := rosa.Std
_, _, _, stage2 := (rosa.Std - 1).NewLLVM() if flagGentoo != "" {
_, _, _, stage3 := rosa.Std.NewLLVM() std -= 3 // magic number to discourage misuse
var checksum pkg.Checksum
if len(flagChecksum) != 0 {
if err = pkg.Decode(&checksum, flagChecksum); err != nil {
return
}
}
rosa.SetGentooStage3(flagGentoo, checksum)
}
_, _, _, stage1 := (std - 2).NewLLVM()
_, _, _, stage2 := (std - 1).NewLLVM()
_, _, _, stage3 := std.NewLLVM()
var ( var (
pathname *check.Absolute pathname *check.Absolute
checksum [2]unique.Handle[pkg.Checksum] checksum [2]unique.Handle[pkg.Checksum]
@@ -153,7 +169,7 @@ func main() {
if flagStage0 { if flagStage0 {
if pathname, _, err = cache.Cure( if pathname, _, err = cache.Cure(
rosa.Std.Load(rosa.Stage0), std.Load(rosa.Stage0),
); err != nil { ); err != nil {
return err return err
} }
@@ -163,6 +179,16 @@ func main() {
return return
}, },
). ).
Flag(
&flagGentoo,
"gentoo", command.StringFlag(""),
"Bootstrap from a Gentoo stage3 tarball",
).
Flag(
&flagChecksum,
"checksum", command.StringFlag(""),
"Checksum of Gentoo stage3 tarball",
).
Flag( Flag(
&flagStage0, &flagStage0,
"stage0", command.BoolFlag(false), "stage0", command.BoolFlag(false),

View File

@@ -2,6 +2,7 @@
package rosa package rosa
import ( import (
"errors"
"log" "log"
"runtime" "runtime"
"slices" "slices"
@@ -101,9 +102,23 @@ func earlyCXXFLAGS() string {
type Toolchain uintptr type Toolchain uintptr
const ( const (
// toolchainBusybox denotes a busybox installation from the busyboxBin // _toolchainBusybox denotes a busybox installation from the busyboxBin
// binary distribution. This is for decompressing unsupported formats. // binary distribution. This is defined as a toolchain to make use of the
toolchainBusybox Toolchain = iota // toolchain abstractions to preprocess toolchainGentoo and is not a real,
// functioning toolchain. It does not contain any compilers.
_toolchainBusybox Toolchain = iota
// toolchainGentoo denotes the toolchain in a Gentoo stage3 tarball. Special
// care must be taken to compile correctly against this toolchain.
toolchainGentoo
// toolchainIntermediateGentoo is like to toolchainIntermediate, but
// compiled against toolchainGentoo.
toolchainIntermediateGentoo
// toolchainStdGentoo is like Std, but bootstrapped from toolchainGentoo.
// This toolchain creates the first [Stage0] distribution.
toolchainStdGentoo
// toolchainStage0 denotes the stage0 toolchain. Special care must be taken // toolchainStage0 denotes the stage0 toolchain. Special care must be taken
// to compile correctly against this toolchain. // to compile correctly against this toolchain.
@@ -125,7 +140,7 @@ const (
// stage0Concat concatenates s and values. If the current toolchain is // stage0Concat concatenates s and values. If the current toolchain is
// toolchainStage0, stage0Concat returns s as is. // toolchainStage0, stage0Concat returns s as is.
func stage0Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S { func stage0Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
if t == toolchainStage0 { if t == toolchainStage0 || t == toolchainGentoo {
return s return s
} }
return slices.Concat(s, values) return slices.Concat(s, values)
@@ -134,7 +149,7 @@ func stage0Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
// stage0ExclConcat concatenates s and values. If the current toolchain is not // stage0ExclConcat concatenates s and values. If the current toolchain is not
// toolchainStage0, stage0ExclConcat returns s as is. // toolchainStage0, stage0ExclConcat returns s as is.
func stage0ExclConcat[S ~[]E, E any](t Toolchain, s S, values ...E) S { func stage0ExclConcat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
if t == toolchainStage0 { if t == toolchainStage0 || t == toolchainGentoo {
return slices.Concat(s, values) return slices.Concat(s, values)
} }
return s return s
@@ -182,6 +197,25 @@ const (
TEarly TEarly
) )
var (
// gentooStage3 is the url of a Gentoo stage3 tarball.
gentooStage3 string
// gentooStage3Checksum is the expected checksum of gentooStage3.
gentooStage3Checksum pkg.Checksum
)
// SetGentooStage3 sets the Gentoo stage3 tarball url and checksum. It panics
// if given zero values or if these values have already been set.
func SetGentooStage3(url string, checksum pkg.Checksum) {
if gentooStage3 != "" {
panic(errors.New("attempting to set Gentoo stage3 url twice"))
}
if url == "" {
panic(errors.New("attempting to set Gentoo stage3 url to the zero value"))
}
gentooStage3, gentooStage3Checksum = url, checksum
}
// New returns a [pkg.Artifact] compiled on this toolchain. // New returns a [pkg.Artifact] compiled on this toolchain.
func (t Toolchain) New( func (t Toolchain) New(
name string, name string,
@@ -197,49 +231,45 @@ func (t Toolchain) New(
var support []pkg.Artifact var support []pkg.Artifact
switch t { switch t {
case toolchainBusybox: case _toolchainBusybox:
name += "-early" name += "-early"
support = slices.Concat([]pkg.Artifact{newBusyboxBin()}, extra) support = slices.Concat([]pkg.Artifact{newBusyboxBin()}, extra)
env = fixupEnviron(env, nil, "/system/bin") env = fixupEnviron(env, nil, "/system/bin")
case toolchainStage0: case toolchainGentoo, toolchainStage0:
name += "-boot" name += "-boot"
var seed string support = append(support, cureEtc{})
switch runtime.GOARCH { if t == toolchainStage0 {
case "amd64": support = append(support, NewStage0())
seed = "c5_FwMnRN8RZpTdBLGYkL4RR8ampdaZN2JbkgrFLe8-QHQAVQy08APVvIL6eT7KW" } else {
case "arm64": support = append(support, _toolchainBusybox.New("gentoo", 0, nil, nil, nil, `
seed = "79uRbRI44PyknQQ9RlFUQrwqplup7vImiIk6klefL8TN-fT42TXMS_v4XszwexCb" tar -C /work -xf /usr/src/stage3.tar.xz
default:
panic("unsupported target " + runtime.GOARCH)
}
support = slices.Concat([]pkg.Artifact{
cureEtc{},
toolchainBusybox.New("stage0", 0, nil, nil, nil, `
tar -C /work -xf /usr/src/stage0.tar.xz
rm -rf /work/dev/ /work/proc/ rm -rf /work/dev/ /work/proc/
ln -vs ../usr/bin /work/bin ln -vs ../usr/bin /work/bin
mkdir -vp /work/system/bin mkdir -vp /work/system/bin
ln -vs ../../bin/sh /work/system/bin (cd /work/system/bin && ln -vs \
`, pkg.Path(AbsUsrSrc.Append("stage0.tar.xz"), false, ../../bin/sh \
../../usr/lib/llvm/*/bin/* \
.)
`, pkg.Path(AbsUsrSrc.Append("stage3.tar.xz"), false,
pkg.NewHTTPGet( pkg.NewHTTPGet(
nil, "https://basement.gensokyo.uk/seed/"+seed, nil, gentooStage3,
mustDecode(seed), gentooStage3Checksum,
), ),
)), )))
}, extra) }
support = slices.Concat(support, extra)
env = fixupEnviron(env, []string{ env = fixupEnviron(env, []string{
EnvTriplet + "=" + triplet(), EnvTriplet + "=" + triplet(),
lcMessages, lcMessages,
"LDFLAGS=" + earlyLDFLAGS(true), "LDFLAGS=" + earlyLDFLAGS(true),
}, "/system/bin", }, "/system/bin",
"/usr/bin", "/usr/bin",
"/usr/lib/llvm/21/bin",
) )
case toolchainIntermediate, Std: case toolchainIntermediateGentoo, toolchainStdGentoo,
if t < Std { toolchainIntermediate, Std:
if t == toolchainIntermediateGentoo || t == toolchainIntermediate {
name += "-std" name += "-std"
} }

View File

@@ -1,6 +1,11 @@
package rosa package rosa
import "hakurei.app/internal/pkg" import (
"runtime"
"sync"
"hakurei.app/internal/pkg"
)
func (t Toolchain) newStage0() pkg.Artifact { func (t Toolchain) newStage0() pkg.Artifact {
musl, compilerRT, runtimes, clang := t.NewLLVM() musl, compilerRT, runtimes, clang := t.NewLLVM()
@@ -37,3 +42,32 @@ tar \
`) `)
} }
func init() { artifactsF[Stage0] = Toolchain.newStage0 } func init() { artifactsF[Stage0] = Toolchain.newStage0 }
var (
// stage0 stores the tarball unpack artifact.
stage0 pkg.Artifact
// stage0Once is for lazy initialisation of stage0.
stage0Once sync.Once
)
// NewStage0 returns a stage0 distribution created from curing [Stage0].
func NewStage0() pkg.Artifact {
stage0Once.Do(func() {
var seed string
switch runtime.GOARCH {
case "amd64":
seed = "tqM1Li15BJ-uFG8zU-XjgFxoN_kuzh1VxrSDVUVa0vGmo-NeWapSftH739sY8EAg"
default:
panic("unsupported target " + runtime.GOARCH)
}
stage0 = pkg.NewHTTPGetTar(
nil, "https://hakurei.app/seed/20260210/"+
"stage0-"+triplet()+".tar.bz2",
mustDecode(seed),
pkg.TarBzip2,
)
})
return stage0
}