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 (
flagGentoo string
flagChecksum string
flagStage0 bool
)
c.NewCommand(
"stage3",
"Check for toolchain 3-stage non-determinism",
func(args []string) (err error) {
_, _, _, stage1 := (rosa.Std - 2).NewLLVM()
_, _, _, stage2 := (rosa.Std - 1).NewLLVM()
_, _, _, stage3 := rosa.Std.NewLLVM()
std := rosa.Std
if flagGentoo != "" {
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 (
pathname *check.Absolute
checksum [2]unique.Handle[pkg.Checksum]
@@ -153,7 +169,7 @@ func main() {
if flagStage0 {
if pathname, _, err = cache.Cure(
rosa.Std.Load(rosa.Stage0),
std.Load(rosa.Stage0),
); err != nil {
return err
}
@@ -162,6 +178,16 @@ func main() {
return
},
).
Flag(
&flagGentoo,
"gentoo", command.StringFlag(""),
"Bootstrap from a Gentoo stage3 tarball",
).
Flag(
&flagChecksum,
"checksum", command.StringFlag(""),
"Checksum of Gentoo stage3 tarball",
).
Flag(
&flagStage0,

View File

@@ -2,6 +2,7 @@
package rosa
import (
"errors"
"log"
"runtime"
"slices"
@@ -101,9 +102,23 @@ func earlyCXXFLAGS() string {
type Toolchain uintptr
const (
// toolchainBusybox denotes a busybox installation from the busyboxBin
// binary distribution. This is for decompressing unsupported formats.
toolchainBusybox Toolchain = iota
// _toolchainBusybox denotes a busybox installation from the busyboxBin
// binary distribution. This is defined as a toolchain to make use of the
// 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
// to compile correctly against this toolchain.
@@ -125,7 +140,7 @@ const (
// stage0Concat concatenates s and values. If the current toolchain is
// toolchainStage0, stage0Concat returns s as is.
func stage0Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
if t == toolchainStage0 {
if t == toolchainStage0 || t == toolchainGentoo {
return s
}
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
// toolchainStage0, stage0ExclConcat returns s as is.
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 s
@@ -182,6 +197,25 @@ const (
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.
func (t Toolchain) New(
name string,
@@ -197,49 +231,45 @@ func (t Toolchain) New(
var support []pkg.Artifact
switch t {
case toolchainBusybox:
case _toolchainBusybox:
name += "-early"
support = slices.Concat([]pkg.Artifact{newBusyboxBin()}, extra)
env = fixupEnviron(env, nil, "/system/bin")
case toolchainStage0:
case toolchainGentoo, toolchainStage0:
name += "-boot"
var seed string
switch runtime.GOARCH {
case "amd64":
seed = "c5_FwMnRN8RZpTdBLGYkL4RR8ampdaZN2JbkgrFLe8-QHQAVQy08APVvIL6eT7KW"
case "arm64":
seed = "79uRbRI44PyknQQ9RlFUQrwqplup7vImiIk6klefL8TN-fT42TXMS_v4XszwexCb"
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
support = append(support, cureEtc{})
if t == toolchainStage0 {
support = append(support, NewStage0())
} else {
support = append(support, _toolchainBusybox.New("gentoo", 0, nil, nil, nil, `
tar -C /work -xf /usr/src/stage3.tar.xz
rm -rf /work/dev/ /work/proc/
ln -vs ../usr/bin /work/bin
mkdir -vp /work/system/bin
ln -vs ../../bin/sh /work/system/bin
`, pkg.Path(AbsUsrSrc.Append("stage0.tar.xz"), false,
(cd /work/system/bin && ln -vs \
../../bin/sh \
../../usr/lib/llvm/*/bin/* \
.)
`, pkg.Path(AbsUsrSrc.Append("stage3.tar.xz"), false,
pkg.NewHTTPGet(
nil, "https://basement.gensokyo.uk/seed/"+seed,
mustDecode(seed),
nil, gentooStage3,
gentooStage3Checksum,
),
)),
}, extra)
)))
}
support = slices.Concat(support, extra)
env = fixupEnviron(env, []string{
EnvTriplet + "=" + triplet(),
lcMessages,
"LDFLAGS=" + earlyLDFLAGS(true),
}, "/system/bin",
"/usr/bin",
"/usr/lib/llvm/21/bin",
)
case toolchainIntermediate, Std:
if t < Std {
case toolchainIntermediateGentoo, toolchainStdGentoo,
toolchainIntermediate, Std:
if t == toolchainIntermediateGentoo || t == toolchainIntermediate {
name += "-std"
}

View File

@@ -1,6 +1,11 @@
package rosa
import "hakurei.app/internal/pkg"
import (
"runtime"
"sync"
"hakurei.app/internal/pkg"
)
func (t Toolchain) newStage0() pkg.Artifact {
musl, compilerRT, runtimes, clang := t.NewLLVM()
@@ -37,3 +42,32 @@ tar \
`)
}
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
}